
import time

import wx
import wx.propgrid as wxpg

import ab_utils as ut


class DirsProperty(wxpg.PyArrayStringProperty):
    def __init__(self, label, name=wxpg.LABEL_AS_NAME, value=[]):
        wxpg.PyArrayStringProperty.__init__(self, label, name, value)

        # Set default delimiter
        self.SetAttribute("Delimiter", ',')

    def GetEditor(self):
        return "TextCtrlAndButton"

    def ValueToString(self, value, flags):
        return self.m_display

    def OnSetValue(self):
        self.GenerateValueAsString()

    def DoSetAttribute(self, name, value):
        # Proper way to call same method from super class
        retval = self.CallSuperMethod("DoSetAttribute", name, value)

        # Must re-generate cached string when delimiter changes
        if name == "Delimiter":
            self.GenerateValueAsString(delim=value)

        return retval

    def GenerateValueAsString(self, delim=None):
        if not delim:
            delim = self.GetAttribute("Delimiter")
            if not delim:
                delim = ','

        ls = self.GetValue()
        if delim == '"' or delim == "'":
            text = ' '.join(['%s%s%s' % (delim, a, delim) for a in ls])
        else:
            text = ', '.join(ls)
        self.m_display = text

    def StringToValue(self, text, argFlags):
        delim = self.GetAttribute("Delimiter")
        if delim == '"' or delim == "'":
            return self.CallSuperMethod("StringToValue", text, 0)

        v = [a.strip() for a in text.split(delim)]
        return (True, v)

    def OnEvent(self, propgrid, primaryEditor, event):
        if event.GetEventType() == wx.wxEVT_COMMAND_BUTTON_CLICKED:
            dlg = wx.DirDialog(propgrid,
                               "Select a directory to be added to the list:")

            if dlg.ShowModal() == wx.ID_OK:
                new_path = dlg.GetPath()
                old_value = self.m_value
                if old_value:
                    new_value = list(old_value)
                    new_value.append(new_path)
                else:
                    new_value = [new_path]
                self.SetValueInEvent(new_value)
                retval = True
            else:
                retval = False

            dlg.Destroy()
            return retval

        return False


class PropertyGrid(wxpg.PropertyGrid):
    def __init__(self, app, parent, template, reader, useOptionName=False):

        wxpg.PropertyGrid.__init__(
            self, parent, -1,
            style=wxpg.PG_AUTO_SORT | wxpg.PG_SPLITTER_AUTO_CENTER)

        KNOWN_TYPES = ('int', 'float', 'bool', 'str', 'color', 'font', 'date')

        self.reader = reader
        self.template = template

        for c, section in (template or dict()).items():
            options = section.get('options', dict())

            optc = 0
            for opt in options:
                item = reader.getItem(opt)
                if item is not None:
                    for a in item.attr:
                        if a in KNOWN_TYPES:
                            optc += 1
                            break

                if optc > 0:
                    break

            if optc == 0:
                continue

            self.Append(wxpg.PropertyCategory(section.get('name', '-')))
            for opt, option in options.items():
                vals = reader.getItem(opt)

                attr = vals.attr
                name = option.get('name', '-') if useOptionName else vals.name
                # read the key with the official interface
                value = reader.readKey(opt, escape=False)
                if 'range' in attr:
                    if value is None:
                        value = dict()
                    if 'dir' in attr:
                        self.Append(DirsProperty(name, value=value.values()))
                    elif 'str' in attr:
                        self.Append(wxpg.ArrayStringProperty(name,
                                    value=value.values()))
                    elif 'int' in attr or 'float' in attr or 'bool' in attr:
                        converted = [str(v) for v in value.values()]
                        self.Append(wxpg.ArrayStringProperty(name,
                                    value=converted))
                elif 'enum' in attr:
                    enum = option.get('enum')
                    if isinstance(enum, (list, tuple)):
                        elist = enum[0]
                        if len(enum) > 1:
                            evalue = enum[1]
                        else:
                            evalue = range(0, len(elist))
                        self.Append(wxpg.EnumProperty(name, name,
                                                      elist, evalue, value))
                elif 'color' in attr:
                    color = ut.int2rgb(value)
                    self.Append(wxpg.ColourProperty(name, value=color))
                elif 'font' in attr:
                    self.Append(wxpg.FontProperty(name, value=value))
                elif 'int' in attr:
                    self.Append(wxpg.IntProperty(name, value=value))
                elif 'bool' in attr:
                    self.Append(wxpg.BoolProperty(name, value=value))
                    self.SetPropertyAttribute(name, "UseCheckbox", True)
                elif 'float' in attr:
                    self.Append(wxpg.FloatProperty(name, value=value))
                elif 'str' in attr:
                    if 'dir' in attr:
                        self.Append(wxpg.DirProperty(name, value=value))
                    elif 'file' in attr:
                        self.Append(wxpg.FileProperty(name, value=value))
                    elif 'date' in attr:
                        tm = time.strptime(value)
                        wtime = wx.DateTimeFromDMY(
                            tm.tm_mday, tm.tm_mon, tm.tm_year)
                        self.Append(wxpg.DateProperty(name, value=wtime))
                    elif value is not None:
                        self.Append(wxpg.StringProperty(name, value=value))
                elif 'time' in attr:
                    if isinstance(value, (int, long, float)):
                        value = time.strftime("%H:%M:%S", time.gmtime(value))
                    self.Append(wxpg.StringProperty(name, value=value))
                elif 'date' in attr:
                    if isinstance(value, (int, long, float)):
                        value = time.gmtime(value)
                    elif isinstance(value, (str, unicode)):
                        value = time.strptime(value)

                    if isinstance(value, time.struct_time):
                        wtime = wx.DateTimeFromDMY(
                            value.tm_mday, value.tm_mon, value.tm_year)
                    else:
                        wtime = wx.DateTime_Now()

                    self.Append(wxpg.DateProperty(name, value=wtime))

    def getValues(self, name=None, value=None):
        if name is None:
            vals = dict()
            # get all properties
            props = self.GetPropertyValues()
            for k, v in props.iteritems():
                vals[k] = v

            return vals

        for c, section in (self.template or dict()).items():
            options = section.get('options', dict())
            for opt, option in options.items():
                vals = self.reader.getItem(opt)
                attr = vals.attr

                if name == vals.name:
                    if 'enum' in attr:
                        enum = option.get('enum')
                        if isinstance(enum, (list, tuple)):
                            elist = enum[0]
                            if len(enum) > 1:
                                evalue = enum[1]
                            else:
                                evalue = range(0, len(elist))

                        offset = elist.index(value)
                        value = evalue[offset]
                    elif 'font' in attr:
                        return None

                    return opt, value

        return None
